"""
管理员服务
处理管理员相关的业务逻辑，包括访问码验证、用户管理、订单管理、商品管理等
"""

import bcrypt
import json
import os
from datetime import datetime, timedelta
from typing import List, Dict, Any, Optional, Tuple
from core.services.data_manager import DataManager
from core.services.order_service import OrderService
from core.services.product_service import ProductService
from core.models.order import Order, OrderStatus
from core.models.user import User
from core.utils.logger import info, warning, error, debug
from core.utils.error_handler import handle_critical_errors


class AdminService:
    """管理员服务类"""
    
    def __init__(self):
        self.data_manager = DataManager()
        self.order_service = OrderService()
        self.product_service = ProductService()
        self.config_file = "admin_config.json"
        self.lockout_file = "admin_lockout.json"
        self._load_config()
    
    def _load_config(self):
        """加载管理员配置"""
        try:
            config_path = os.path.join(self.data_manager.data_dir, self.config_file)
            if os.path.exists(config_path):
                with open(config_path, 'r', encoding='utf-8') as f:
                    self.config = json.load(f)
            else:
                # 使用默认配置
                self.config = {
                    "access_code": "admin2025",
                    "access_code_hash": "",
                    "max_login_attempts": 3,
                    "lockout_duration_minutes": 5,
                    "low_stock_threshold": 10,
                    "admin_email_domains": ["admin", "manager"],
                    "session_timeout_minutes": 30
                }
                self._save_config()
        except Exception as e:
            error(f"加载管理员配置失败: {e}")
            self.config = {"access_code": "admin2025", "max_login_attempts": 3}
    
    def _save_config(self):
        """保存管理员配置"""
        try:
            config_path = os.path.join(self.data_manager.data_dir, self.config_file)
            with open(config_path, 'w', encoding='utf-8') as f:
                json.dump(self.config, f, ensure_ascii=False, indent=2)
        except Exception as e:
            error(f"保存管理员配置失败: {e}")
    
    def _get_lockout_data(self) -> Dict[str, Any]:
        """获取锁定数据"""
        try:
            lockout_path = os.path.join(self.data_manager.data_dir, self.lockout_file)
            if os.path.exists(lockout_path):
                with open(lockout_path, 'r', encoding='utf-8') as f:
                    return json.load(f)
            return {"attempts": 0, "last_attempt": None, "locked_until": None}
        except Exception:
            return {"attempts": 0, "last_attempt": None, "locked_until": None}
    
    def _save_lockout_data(self, data: Dict[str, Any]):
        """保存锁定数据"""
        try:
            lockout_path = os.path.join(self.data_manager.data_dir, self.lockout_file)
            with open(lockout_path, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
        except Exception as e:
            error(f"保存锁定数据失败: {e}")
    
    def verify_access_code(self, code: str) -> Tuple[bool, str]:
        """
        验证管理员访问码
        
        Args:
            code: 输入的访问码
            
        Returns:
            tuple: (是否验证成功, 错误消息)
        """
        try:
            # 检查是否被锁定
            lockout_data = self._get_lockout_data()
            if lockout_data.get("locked_until"):
                locked_until = datetime.fromisoformat(lockout_data["locked_until"])
                if datetime.now() < locked_until:
                    remaining = locked_until - datetime.now()
                    return False, f"访问码被锁定，请 {remaining.seconds // 60 + 1} 分钟后重试"
            
            # 验证访问码
            stored_code = self.config.get("access_code", "admin2025")
            if code == stored_code:
                # 验证成功，清除锁定数据
                self._save_lockout_data({"attempts": 0, "last_attempt": None, "locked_until": None})
                info("管理员访问码验证成功")
                return True, ""
            else:
                # 验证失败，记录尝试次数
                attempts = lockout_data.get("attempts", 0) + 1
                max_attempts = self.config.get("max_login_attempts", 3)
                
                if attempts >= max_attempts:
                    # 达到最大尝试次数，锁定
                    lockout_duration = self.config.get("lockout_duration_minutes", 5)
                    locked_until = datetime.now() + timedelta(minutes=lockout_duration)
                    self._save_lockout_data({
                        "attempts": attempts,
                        "last_attempt": datetime.now().isoformat(),
                        "locked_until": locked_until.isoformat()
                    })
                    warning(f"管理员访问码验证失败次数过多，已锁定 {lockout_duration} 分钟")
                    return False, f"访问码错误次数过多，已锁定 {lockout_duration} 分钟"
                else:
                    # 记录失败尝试
                    self._save_lockout_data({
                        "attempts": attempts,
                        "last_attempt": datetime.now().isoformat(),
                        "locked_until": None
                    })
                    remaining = max_attempts - attempts
                    return False, f"访问码错误，还有 {remaining} 次尝试机会"
                    
        except Exception as e:
            error(f"验证访问码时发生错误: {e}")
            return False, "验证访问码时发生错误"
    
    def get_all_users_with_stats(self) -> List[Dict[str, Any]]:
        """获取所有用户及其统计信息"""
        try:
            users = self.data_manager.load_users()
            users_with_stats = []
            
            for user_data in users:
                user_id = user_data.get('user_id', '')
                user_orders = self.order_service.get_user_orders(user_id)
                
                # 计算用户统计
                total_orders = len(user_orders)
                total_spent = sum(order.total for order in user_orders)
                completed_orders = len([o for o in user_orders if o.status == OrderStatus.COMPLETED])
                
                user_with_stats = {
                    **user_data,
                    'total_orders': total_orders,
                    'total_spent': total_spent,
                    'completed_orders': completed_orders,
                    'last_order_date': max([o.created_at for o in user_orders], default=None)
                }
                users_with_stats.append(user_with_stats)
            
            # 按总消费金额排序
            users_with_stats.sort(key=lambda x: x.get('total_spent', 0), reverse=True)
            return users_with_stats
            
        except Exception as e:
            error(f"获取用户统计信息失败: {e}")
            return []
    
    def get_all_orders_with_user_info(self) -> List[Dict[str, Any]]:
        """获取所有订单及关联的用户信息"""
        try:
            orders = self.order_service.get_all_orders()
            users = {user['user_id']: user for user in self.data_manager.load_users()}
            
            orders_with_user_info = []
            for order in orders:
                user_info = users.get(order.user_id, {})
                order_dict = order.to_dict()
                order_dict['user_info'] = {
                    'username': user_info.get('username', '未知用户'),
                    'email': user_info.get('email', ''),
                    'role': user_info.get('role', 'customer')
                }
                orders_with_user_info.append(order_dict)
            
            # 按创建时间倒序排列
            orders_with_user_info.sort(key=lambda x: x.get('created_at', ''), reverse=True)
            return orders_with_user_info
            
        except Exception as e:
            error(f"获取订单及用户信息失败: {e}")
            return []
    
    def batch_update_order_status(self, order_ids: List[str], new_status: OrderStatus) -> Tuple[int, int]:
        """
        批量更新订单状态
        
        Args:
            order_ids: 订单ID列表
            new_status: 新状态
            
        Returns:
            tuple: (成功数量, 失败数量)
        """
        success_count = 0
        fail_count = 0
        
        for order_id in order_ids:
            try:
                if self.order_service.update_order_status(order_id, new_status):
                    success_count += 1
                    info(f"批量更新订单状态成功: {order_id} -> {new_status}")
                else:
                    fail_count += 1
                    warning(f"批量更新订单状态失败: {order_id}")
            except Exception as e:
                fail_count += 1
                error(f"批量更新订单状态异常: {order_id} - {e}")
        
        return success_count, fail_count
    
    def get_product_sales_stats(self) -> List[Dict[str, Any]]:
        """获取商品销售统计"""
        try:
            products = self.data_manager.load_products()
            orders = self.order_service.get_all_orders()
            
            # 统计每个商品的销售数据
            product_stats = {}
            for order in orders:
                if order.status == OrderStatus.COMPLETED:  # 只统计已完成的订单
                    for item in order.items:
                        product_id = item.product_id
                        if product_id not in product_stats:
                            product_stats[product_id] = {
                                'total_sold': 0,
                                'total_revenue': 0.0,
                                'order_count': 0
                            }
                        
                        product_stats[product_id]['total_sold'] += item.quantity
                        product_stats[product_id]['total_revenue'] += item.subtotal
                        product_stats[product_id]['order_count'] += 1
            
            # 返回所有商品（包括没有销售记录的）
            result = []
            for product in products:
                product_id = product.get('product_id', '')
                product_data = {
                    'product_id': product_id,
                    'name': product.get('name', ''),
                    'price': product.get('price', 0),
                    'stock': product.get('stock', 0),
                    'category': product.get('category', ''),
                    'description': product.get('description', ''),
                    'created_at': product.get('created_at', ''),
                    'updated_at': product.get('updated_at', ''),
                    'seller_id': product.get('seller_id', ''),
                    # 销售统计
                    'sales_count': product_stats.get(product_id, {}).get('total_sold', 0),
                    'total_revenue': product_stats.get(product_id, {}).get('total_revenue', 0.0),
                    'order_count': product_stats.get(product_id, {}).get('order_count', 0)
                }
                result.append(product_data)
            
            # 按销售额排序
            result.sort(key=lambda x: x.get('total_revenue', 0), reverse=True)
            return result
            
        except Exception as e:
            error(f"获取商品销售统计失败: {e}")
            return []
    
    def get_low_stock_products(self, threshold: int = None) -> List[Dict[str, Any]]:
        """获取低库存商品"""
        try:
            if threshold is None:
                threshold = self.config.get('low_stock_threshold', 10)
            
            products = self.data_manager.load_products()
            low_stock_products = []
            
            for product in products:
                stock = product.get('stock', 0)
                if stock <= threshold:
                    low_stock_products.append({
                        **product,
                        'stock_status': 'low' if stock > 0 else 'out_of_stock'
                    })
            
            # 按库存数量排序
            low_stock_products.sort(key=lambda x: x.get('stock', 0))
            return low_stock_products
            
        except Exception as e:
            error(f"获取低库存商品失败: {e}")
            return []
    
    def update_product_stock(self, product_id: str, new_stock: int) -> bool:
        """更新商品库存"""
        try:
            products = self.data_manager.load_products()
            
            for product in products:
                if product.get('product_id') == product_id:
                    old_stock = product.get('stock', 0)
                    product['stock'] = max(0, new_stock)  # 确保库存不为负数
                    
                    # 保存更新
                    self.data_manager.save_products(products)
                    
                    info(f"商品库存更新成功: {product_id} {old_stock} -> {product['stock']}")
                    return True
            
            warning(f"未找到商品: {product_id}")
            return False
            
        except Exception as e:
            error(f"更新商品库存失败: {e}")
            return False
    
    def get_system_statistics(self, start_date: str = None, end_date: str = None) -> Dict[str, Any]:
        """获取系统统计数据"""
        try:
            # 获取所有订单
            all_orders = self.order_service.get_all_orders()
            
            # 时间筛选
            if start_date and end_date:
                start_dt = datetime.fromisoformat(start_date)
                end_dt = datetime.fromisoformat(end_date)
                filtered_orders = []
                for order in all_orders:
                    try:
                        # 处理created_at可能是字符串或datetime对象的情况
                        if isinstance(order.created_at, str):
                            order_dt = datetime.fromisoformat(order.created_at)
                        else:
                            order_dt = order.created_at
                        
                        if start_dt <= order_dt <= end_dt:
                            filtered_orders.append(order)
                    except (ValueError, TypeError) as e:
                        error(f"解析订单时间失败: {order.order_id} - {e}")
                        continue
            else:
                filtered_orders = all_orders
            
            # 计算统计数据
            total_orders = len(filtered_orders)
            total_revenue = sum(order.total for order in filtered_orders)
            
            # 按状态统计
            status_stats = {}
            for status in OrderStatus:
                status_orders = [o for o in filtered_orders if o.status == status]
                status_stats[status.value] = {
                    'count': len(status_orders),
                    'revenue': sum(o.total for o in status_orders)
                }
            
            # 用户统计
            users = self.data_manager.load_users()
            user_stats = {
                'total_users': len(users),
                'customers': len([u for u in users if u.get('role') == 'customer']),
                'sellers': len([u for u in users if u.get('role') == 'seller']),
                'admins': len([u for u in users if u.get('role') == 'admin'])
            }
            
            # 商品统计
            products = self.data_manager.load_products()
            product_stats = {
                'total_products': len(products),
                'total_stock': sum(p.get('stock', 0) for p in products),
                'low_stock_count': len(self.get_low_stock_products())
            }
            
            return {
                'period': {
                    'start_date': start_date,
                    'end_date': end_date
                },
                'orders': {
                    'total_orders': total_orders,
                    'total_revenue': total_revenue,
                    'average_order_value': total_revenue / total_orders if total_orders > 0 else 0,
                    'status_breakdown': status_stats
                },
                'users': user_stats,
                'products': product_stats
            }
            
        except Exception as e:
            error(f"获取系统统计失败: {e}")
            return {}
    
    def export_statistics(self, data: Dict[str, Any], filename: str) -> bool:
        """导出统计数据到文件"""
        try:
            export_path = os.path.join(self.data_manager.data_dir, filename)
            
            with open(export_path, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2, default=str)
            
            info(f"统计数据导出成功: {export_path}")
            return True
            
        except Exception as e:
            error(f"导出统计数据失败: {e}")
            return False
    
    def is_admin_user(self, user_id: str) -> bool:
        """检查用户是否为管理员"""
        try:
            users = self.data_manager.load_users()
            for user in users:
                if user.get('user_id') == user_id and user.get('role') == 'admin':
                    return True
            return False
        except Exception as e:
            error(f"检查管理员权限失败: {e}")
            return False
    
    def update_user_info(self, user_id: str, **updates) -> bool:
        """更新用户信息
        
        Args:
            user_id: 用户ID
            updates: 要更新的字段字典
            
        Returns:
            bool: 更新是否成功
        """
        try:
            users = self.data_manager.load_users()
            target = None
            
            # 查找目标用户
            for user in users:
                if user.get('user_id') == user_id:
                    target = user
                    break
            
            if not target:
                warning(f"用户不存在: {user_id}")
                return False
            
            # 验证更新的字段
            allowed_updates = ['username', 'email', 'role']
            for key, value in updates.items():
                if key in allowed_updates:
                    # 检查用户名和邮箱的唯一性
                    if key in ['username', 'email']:
                        for other_user in users:
                            if other_user.get('user_id') != user_id and other_user.get(key) == value:
                                error(f"{key} 已存在: {value}")
                                return False
                    
                    target[key] = value
                    
                    # 如果更新角色，同时更新 roles 数组
                    if key == 'role':
                        new_role = value
                        # 确保 roles 数组包含新角色
                        if 'roles' not in target or not isinstance(target['roles'], list):
                            target['roles'] = [new_role]
                        elif new_role not in target['roles']:
                            # 如果是切换到新角色，替换当前角色
                            target['roles'] = [new_role]
                    
                    info(f"更新用户 {key}: {user_id} -> {value}")
            
            # 保存更新
            self.data_manager.save_users(users)
            info(f"用户信息更新成功: {user_id}")
            return True
            
        except Exception as e:
            error(f"更新用户信息失败: {e}")
            return False
    
    def update_user_role(self, user_id: str, new_role: str) -> bool:
        """更改用户角色
        
        Args:
            user_id: 用户ID
            new_role: 新角色
            
        Returns:
            bool: 更新是否成功
        """
        try:
            valid_roles = ['customer', 'seller', 'admin']
            if new_role not in valid_roles:
                error(f"无效的角色: {new_role}")
                return False
            
            return self.update_user_info(user_id, role=new_role)
            
        except Exception as e:
            error(f"更改用户角色失败: {e}")
            return False
    
    def reset_user_password(self, user_id: str, new_password: str) -> bool:
        """重置用户密码
        
        Args:
            user_id: 用户ID
            new_password: 新密码
            
        Returns:
            bool: 重置是否成功
        """
        try:
            # 验证密码强度
            from core.models.user import User
            is_valid, error_msg = User.validate_password_strength(new_password)
            if not is_valid:
                error(f"密码不符合要求: {error_msg}")
                return False
            
            users = self.data_manager.load_users()
            target = None
            
            # 查找目标用户
            for user in users:
                if user.get('user_id') == user_id:
                    target = user
                    break
            
            if not target:
                warning(f"用户不存在: {user_id}")
                return False
            
            # 生成新密码哈希
            new_password_hash = User._hash_password(new_password)
            target['password_hash'] = new_password_hash
            
            # 保存更新
            self.data_manager.save_users(users)
            info(f"用户密码重置成功: {user_id}")
            return True
            
        except Exception as e:
            error(f"重置用户密码失败: {e}")
            return False
    
    def update_product_info(self, product_id: str, **updates) -> bool:
        """更新商品信息
        
        Args:
            product_id: 商品ID
            updates: 要更新的字段字典
            
        Returns:
            bool: 更新是否成功
        """
        try:
            products = self.data_manager.load_products()
            target = None
            
            # 查找目标商品
            for product in products:
                if product.get('product_id') == product_id:
                    target = product
                    break
            
            if not target:
                warning(f"商品不存在: {product_id}")
                return False
            
            # 验证更新的字段
            allowed_updates = ['name', 'price', 'description', 'category', 'image_path']
            for key, value in updates.items():
                if key in allowed_updates:
                    # 验证价格
                    if key == 'price' and (not isinstance(value, (int, float)) or value < 0):
                        error(f"价格必须是非负数: {value}")
                        return False
                    
                    target[key] = value
                    info(f"更新商品 {key}: {product_id} -> {value}")
            
            # 更新修改时间
            target['updated_at'] = datetime.now().isoformat()
            
            # 保存更新
            self.data_manager.save_products(products)
            info(f"商品信息更新成功: {product_id}")
            return True
            
        except Exception as e:
            error(f"更新商品信息失败: {e}")
            return False
    
    def adjust_product_stock(self, product_id: str, amount: int, operation: str = 'add') -> bool:
        """调整商品库存
        
        Args:
            product_id: 商品ID
            amount: 调整数量
            operation: 操作类型 ('add', 'subtract', 'set')
            
        Returns:
            bool: 调整是否成功
        """
        try:
            if not isinstance(amount, int) or amount < 0:
                error(f"库存数量必须是非负整数: {amount}")
                return False
            
            valid_operations = ['add', 'subtract', 'set']
            if operation not in valid_operations:
                error(f"无效的操作类型: {operation}")
                return False
            
            products = self.data_manager.load_products()
            target = None
            
            # 查找目标商品
            for product in products:
                if product.get('product_id') == product_id:
                    target = product
                    break
            
            if not target:
                warning(f"商品不存在: {product_id}")
                return False
            
            old_stock = target.get('stock', 0)
            
            # 根据操作类型调整库存
            if operation == 'add':
                new_stock = old_stock + amount
            elif operation == 'subtract':
                new_stock = max(0, old_stock - amount)  # 确保库存不为负数
            else:  # set
                new_stock = amount
            
            target['stock'] = new_stock
            target['updated_at'] = datetime.now().isoformat()
            
            # 保存更新
            self.data_manager.save_products(products)
            info(f"商品库存调整成功: {product_id} {old_stock} -> {new_stock} ({operation} {amount})")
            return True
            
        except Exception as e:
            error(f"调整商品库存失败: {e}")
            return False
    
    def add_new_product(self, product_data: dict):
        """添加新商品
        
        Args:
            product_data: 商品数据字典，包含 name, price, description, category, stock 等字段
            
        Returns:
            Product对象: 添加成功返回商品对象，失败返回None
        """
        try:
            # 使用 ProductService 添加商品
            product = self.product_service.add_product(product_data)
            
            if product:
                info(f"Successfully added product: {product.name} (ID: {product.product_id})")
                return product
            else:
                return None
            
        except Exception as e:
            error(f"Failed to add product: {e}")
            return None
    
    def delete_product(self, product_id: str) -> bool:
        """删除商品
        
        Args:
            product_id: 商品ID
            
        Returns:
            bool: 删除是否成功
        """
        try:
            products = self.data_manager.load_products()
            
            # 查找并删除目标商品
            for i, product in enumerate(products):
                if product.get('product_id') == product_id:
                    deleted_product = products.pop(i)
                    self.data_manager.save_products(products)
                    info(f"商品删除成功: {product_id} - {deleted_product.get('name', '')}")
                    return True
            
            warning(f"商品不存在: {product_id}")
            return False
            
        except Exception as e:
            error(f"删除商品失败: {e}")
            return False


